<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\service\jwt;

use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;
use think\Exception;
use think\facade\Config;
use think\facade\Cache;

class IndexJwtService{

    /**
     * @param array $info
     * @param string $type
     * @param $exp
     * @param $key
     * @param array $params
     * @return array
     * @day 2021/07/26
     */
    public function createToken(array $info, string $type, $exp, array $params = [])
    {
        $time = time();
        $host = app('request')->host();
        $params += [
            'iss' => $host,
            'aud' => $type,
            'iat' => $time,
            'nbf' => $time,
            'exp' => $exp,
            'data'=>[
                'user_id'=>$info['id'],
            ],
        ];
        $key = config('index.jwtUserKey');
        $token = JWT::encode($params, $key,'HS256');
        $backData['token'] = $token;
        $backData['out'] = $exp;
        return $backData;
    }

    //验证token
    public function checkToken($token)
    {

        $key = config('index.jwtUserKey');
        $status = ['code'=>1,'result'=>[],'status'=>100];
        try {
            JWT::$leeway = 60;//当前时间减去60，把时间留点余地
            $decoded = JWT::decode($token,new Key($key,'HS256')); //HS256方式，这里要和签发的时候对应
            $arr = (array)$decoded;
            if($arr['exp']>time()){
                return ['code'=>0,'data'=>$arr,'message'=>'已登陆','status'=>200];
            }
            $status['msg'] = "登录信息已过期，请重新登录";
            return $status;

        } catch (\Firebase\JWT\SignatureInvalidException $e) { //签名不正确
            $status['msg'] = "签名不正确";
            return $status;
        } catch (\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用
            $status['msg'] = "token失效";
            return $status;
        } catch (\Firebase\JWT\ExpiredException $e) { // token过期
            $status['msg'] = "token过期";
            return $status;
        } catch (Exception $e) { //其他错误
            $status['msg'] = "未知错误";
            $status['status'] = 428;
            return $status;
        }
    }

    /**
     * @param string $token
     * @return object
     * @throws SignatureInvalidException    Provided JWT was invalid because the signature verification failed
     * @throws BeforeValidException         Provided JWT is trying to be used before it's eligible as defined by 'nbf'
     * @throws BeforeValidException         Provided JWT is trying to be used before it's been created as defined by 'iat'
     * @throws ExpiredException             Provided JWT has since expired, as defined by the 'exp' claim
     * @throws UnexpectedValueException     Provided JWT was invalid
     * @author xaboy
     * @day 2020-04-09
     */
    public function parseToken(string $token)
    {
        return JWT::decode($token, config('index.jwtUserKey'), array('HS256'));
    }

    /**
     * @param string $token
     * @return object
     * @author xaboy
     * @day 2020-04-10
     */
    public function decode(string $token)
    {
        $tks = explode('.', $token);
        if (count($tks) != 3)
            throw new AuthException('Invalid token');

        if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($tks[1])))
            throw new AuthException('Invalid token');

        return $payload;
    }

    /**
     * 缓存token
     * @param string $token
     * @param int $exp
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function cacheToken(string $token, int $exp)
    {
        Cache::store('file')->set('user_' . $token, time() + $exp, $exp);
    }

    /**
     * @param string $token
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function updateToken(string $token)
    {
        Cache::store('file')->set('user_' . $token, time(), intval(config('index.user_token_valid_exp', 15)) * 24 * 60 * 60);
    }

}
